/**
 * 显示隐藏 shadow
 * @param {HTMLElement} el 绑定的 DOM
 */

const processElement = (el) => {
  const scrollHeight = el.scrollHeight
  const clientHeight = el.clientHeight

  const { headShadowEl, tailShadowEl } = el.__scrollShadowData__

  if (el.scrollTop < 10) {
    headShadowEl.classList.remove('is-show')
  } else {
    headShadowEl.classList.add('is-show')
  }

  if (scrollHeight - el.scrollTop - clientHeight < 10) {
    tailShadowEl.classList.remove('is-show')
  } else {
    tailShadowEl.classList.add('is-show')
  }
}

/**
 * 处理滚动事件
 * @param {Event} e 事件对象
 */
function onScroll (e) {
  processElement(e.target)
}

/**
 * 绑定 action
 * @param {HTMLElement} el 绑定的 DOM
 * @param {Object} binding 绑定信息
 */
const bindScrollShadow = (el) => {
  const tailShadowEl = document.createElement('div')
  const headShadowEl = document.createElement('div')

  el.classList.add('scroll-shadown-content')

  el.__scrollShadowData__ = {
    tailShadowEl,
    headShadowEl
  }
  tailShadowEl.classList.add('scroll-bottom-shadow')
  headShadowEl.classList.add('scroll-top-shadow')

  el.addEventListener('scroll', onScroll)
  el.appendChild(tailShadowEl)
  el.insertBefore(headShadowEl, el.firstChild)

  let recordHeight = 0
  const mo = new MutationObserver(() => {
    const currentHeight = el.scrollHeight
    if (recordHeight !== currentHeight) {
      recordHeight = currentHeight
      processElement(el)
    }
  })
  mo.observe(el, {
    childList: true,
    attributes: true,
    characterData: true,
    subtree: true
  })
  el.__scrollShadowData__.mo = mo
}

/**
 * 解绑 action
 * @param {HTMLElement} el 绑定的 DOM
 * @param {Object} binding 绑定信息
 */
const unbindScrollShadow = (el) => {
  const { headShadowEl, tailShadowEl, mo } = el.__scrollShadowData__

  el.classList.remove('scroll-shadown-content')
  el.removeEventListener('scroll', onScroll)
  mo.disconnect()
  headShadowEl.remove()
  tailShadowEl.remove()
}

export default {
  install (Vue) {
    Vue.directive('scroll-shadow', {
      bind: bindScrollShadow,
      unbind: unbindScrollShadow
    })
  }
}
